package org.imraniqbal.engine;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.io.IOException;
import java.io.InputStream;
import java.util.Vector;

import javax.imageio.ImageIO;
import javax.swing.JPanel;


/**
 * @author  imran
 */
public abstract class GamePanel extends JPanel{
	private static final long serialVersionUID = 8431217126159189016L;
	/**
	 * @uml.property  name="game"
	 * @uml.associationEnd  
	 */
	private Game game;
	private Color mazeColor;
	private Color bgColor;
	private Dimension d;
	/**
	 * @uml.property  name="gc"
	 * @uml.associationEnd  
	 */
	private GameController gc;
	public final static int defaultTileSize = 19; //in pixels
	
	/**
	 * Creates a game panel that can be added to a JFrame for a game
	 * @param g instance of game.
	 * @author imran
	 */
	public GamePanel(Game g){
		this.game = g;
		setFocusable(true);
		d = new Dimension(this.game.getMap().getX() * defaultTileSize, this.game.getMap().getY() * defaultTileSize);
		setPreferredSize(d);
		setMazeColor(new Color(0,255,0));
		setBgColor(new Color(0,0,0));
		
		setBackground(bgColor);
		setDoubleBuffered(true);
		gc = new GameController(g, this);
		setGc(gc);

	}
	/**
	 * Creates a game panel that can be added to a JFrame for a game
	 * @param g instance of the game
	 * @param mazeColor Color of maze walls
	 * @param bgColor Color of maze background
	 * @author imran
	 */
	public GamePanel(Game g, Color mazeColor, Color bgColor){
		this(g);
		setMazeColor(mazeColor);
		setBgColor(bgColor);
	}
	/**
	 * (non-Javadoc)
	 * @see javax.swing.JComponent#addNotify()
	 */
	public void addNotify() {
        super.addNotify();
    }
	
	/**
	 * @param game
	 * @author  imran
	 * @uml.property  name="game"
	 */
	public void setGame(Game game) {
		this.game = game;
	}

	/**
	 * Changes current background colour
	 * @param color   New color for background
	 * @author  imran
	 * @uml.property  name="bgColor"
	 */
	public void setBgColor(Color color){
		this.bgColor = color;
	}
	
	/**
	 * Changes current wall colour
	 * @param color   New color for walls in the map
	 * @author  imran
	 * @uml.property  name="mazeColor"
	 */
	public void setMazeColor( Color color){
		this.mazeColor = color;
	}
	
	/**
	 * @return   returns instance of current game
	 * @author  imran
	 * @uml.property  name="game"
	 */
	public Game getGame() {
		return game;
	}
	
	/**
	 * Provides a simple draw method
	 * @param image Image to be drawn
	 * @param y Y co-ordinate on canvas of whare Image should be drawn
	 * @param x X co-ordinate on canvas of where Image should be drawn
	 * @param g2d Instance of current Graphics on which things are to be drawn
	 * @author imran
	 */
	public void DrawImage(Graphics2D g2d, int x, int y, Image image) {
        g2d.drawImage(image, x, y, this);
    }

	/**
	 * Starts a new game
	 * @author imran
	 */
	public abstract void newGame();
	/**
	 * (non-Javadoc)		// TODO Auto-generated method stub
		
	}
	 * @see javax.swing.JComponent#paint(java.awt.Graphics)
	 */
	public void paint(Graphics g){
		super.paint(g);

	    Graphics2D g2d = (Graphics2D) g;

	    g2d.setColor(bgColor);
	    g2d.fillRect(0, 0, d.width, d.height);

	    DrawMap(g2d);
	    
	    Toolkit.getDefaultToolkit().sync();
	    g.dispose();

		
	}
	/**
	 * Create an Image specified by a filepath
	 * @param filepath the path to the file
	 * @return An Image of the image
	 * @author imran
	 */
	public Image creatImage(InputStream filepath){
		//return new ImageIcon(filepath).getImage(); 
		//return getToolkit().createImage(filepath); //this is only for the jar
		try {
			return ImageIO.read(filepath);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	/**
	 * Draws everything loaded onto current map that is contained in the current Game
	 * @param g2d Instance of Graphics on which images are to be drawn
	 * @author imran
	 */
	private void DrawMap(Graphics2D g2d) {
		for(int x = 0; x < this.getGame().getMap().getX(); x++){
			for(int y = 0; y < this.getGame().getMap().getY(); y++){
				if(this.getGame().getMap().isWall(x,y)){
					g2d.setColor(mazeColor);
					g2d.drawRect(x*defaultTileSize, y*defaultTileSize, defaultTileSize, defaultTileSize);
				}
				if(!this.getGame().getMap().isEmpty(x, y) && !this.getGame().getMap().isWall(x, y)){
					DrawMappable(this.getGame().getMap().getMappable(x, y),g2d);
				}
			}
		}
	}
	/**
	 * Abstract method to allow games to be able to paint their own mappables
	 * @param mappable Vector of mappables to be drawn
	 * @param g2d Graphics2D instance
	 * @author imran
	 */
	protected abstract void DrawMappable(Vector<Mappable> mappable, Graphics2D g2d);
	
	/**
	 * @return  Returns current GameController
	 * @uml.property  name="gc"
	 */
	public GameController getGc() {
		return this.gc;
	}
	/**
	 * Allows you to set a gamecontroller
	 * @param gc  game controller that you wish to add
	 * @uml.property  name="gc"
	 */
	public void setGc(GameController gc) {
		addKeyListener(gc);
	}
	/**
	 * Allows you to remove a gameController
	 * @param gc gamecontroller that you wish to remove
	 */
	public void removeGc(GameController gc){
		removeKeyListener(getGc());
	}
}
